Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace sort implementations #124032

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open

Conversation

Voultapher
Copy link
Contributor

@Voultapher Voultapher commented Apr 16, 2024

This PR replaces the sort implementations with tailor-made ones that strike a balance of run-time, compile-time and binary-size, yielding run-time and compile-time improvements. Regressing binary-size for slice::sort while improving it for slice::sort_unstable. All while upholding the existing soft and hard safety guarantees, and even extending the soft guarantees, detecting strict weak ordering violations with a high chance and reporting it to users via a panic.

  • slice::sort -> driftsort design document, includes detailed benchmarks and analysis.

  • slice::sort_unstable -> ipnsort design document, includes detailed benchmarks and analysis.

Why should we change the sort implementations?

In the 2023 Rust survey, one of the questions was: "In your opinion, how should work on the following aspects of Rust be prioritized?". The second place was "Runtime performance" and the third one "Compile Times". This PR aims to improve both.

Why is this one big PR and not multiple?

  • The current documentation gives performance recommendations for slice::sort and slice::sort_unstable. If for example only one of them were to be changed, this advice would be misleading for some Rust versions. By replacing them atomically, the advice remains largely unchanged, and users don't have to change their code.
  • driftsort and ipnsort share a substantial part of their implementations.
  • The implementation of select_nth_unstable uses internals of slice::sort_unstable, which makes it impractical to split changes.

This PR is a collaboration with @orlp.

@rustbot
Copy link
Collaborator

rustbot commented Apr 16, 2024

r? @jhpratt

rustbot has assigned @jhpratt.
They will have a look at your PR within the next two weeks and either review your PR or reassign to another reviewer.

Use r? to explicitly pick a reviewer

@rustbot rustbot added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs Relevant to the library team, which will review and decide on the PR/issue. labels Apr 16, 2024
@Voultapher
Copy link
Contributor Author

r? thomcc

@rustbot rustbot assigned thomcc and unassigned jhpratt Apr 16, 2024
@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@rust-log-analyzer

This comment has been minimized.

@matthiaskrgr
Copy link
Member

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Apr 16, 2024
@rust-log-analyzer

This comment has been minimized.

@Voultapher

This comment was marked as outdated.

@rustbot rustbot assigned joboet and thomcc and unassigned thomcc and joboet Apr 17, 2024
@Kobzol
Copy link
Contributor

Kobzol commented Apr 17, 2024

@bors try

(looks like the try build didn't get through)

@bors
Copy link
Contributor

bors commented Apr 17, 2024

⌛ Trying commit eeee5de with merge a4132fa...

bors added a commit to rust-lang-ci/rust that referenced this pull request Apr 17, 2024
Replace sort implementations

This PR replaces the sort implementations with tailor-made ones that strike a balance of run-time, compile-time and binary-size, yielding run-time and compile-time improvements. Regressing binary-size for `slice::sort` while improving it for `slice::sort_unstable`. All while upholding the existing soft and hard safety guarantees, and even extending the soft guarantees, detecting strict weak ordering violations with a high chance and reporting it to users via a panic.

* `slice::sort` -> driftsort [design document](https://github.com/Voultapher/sort-research-rs/blob/main/writeup/driftsort_introduction/text.md)

* `slice::sort_unstable` -> ipnsort [design document](https://github.com/Voultapher/sort-research-rs/blob/main/writeup/ipnsort_introduction/text.md)

#### Why should we change the sort implementations?

In the [2023 Rust survey](https://blog.rust-lang.org/2024/02/19/2023-Rust-Annual-Survey-2023-results.html#challenges), one of the questions was: "In your opinion, how should work on the following aspects of Rust be prioritized?". The second place was "Runtime performance" and the third one "Compile Times". This PR aims to improve both.

#### Why is this one big PR and not multiple?

* The current documentation gives performance recommendations for `slice::sort` and `slice::sort_unstable`. If for example only one of them were to changed, this advise may be misleading for some Rust versions. By replacing them atomically, the advise remains largely unchanged, and users don't have to change their code.
* driftsort and ipnsort share a substantial part of their implementations.
* The implementation of `select_nth_unstable` uses internals of `slice::sort_unstable`, which makes it impractical to split changes.

---

This PR is a collaboration with `@orlp.`
@bors
Copy link
Contributor

bors commented Apr 17, 2024

☀️ Try build successful - checks-actions
Build commit: a4132fa (a4132fa857b71c2cec6719753cc4f31d6f7ea3c4)

@rust-timer

This comment has been minimized.

@rust-timer
Copy link
Collaborator

Finished benchmarking commit (a4132fa): comparison URL.

Overall result: ❌ regressions - ACTION NEEDED

Benchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. While you can manually mark this PR as fit for rollup, we strongly recommend not doing so since this PR may lead to changes in compiler perf.

Next Steps: If you can justify the regressions found in this try perf run, please indicate this with @rustbot label: +perf-regression-triaged along with sufficient written justification. If you cannot justify the regressions please fix the regressions and do another perf run. If the next run shows neutral or positive results, the label will be automatically removed.

@bors rollup=never
@rustbot label: -S-waiting-on-perf +perf-regression

Instruction count

This is a highly reliable metric that was used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
2.2% [0.2%, 18.4%] 44
Regressions ❌
(secondary)
1.1% [0.2%, 4.3%] 9
Improvements ✅
(primary)
-0.4% [-0.5%, -0.3%] 7
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 1.9% [-0.5%, 18.4%] 51

Max RSS (memory usage)

Results

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
3.6% [1.0%, 7.3%] 10
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
-3.2% [-3.8%, -2.0%] 3
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 2.1% [-3.8%, 7.3%] 13

Cycles

Results

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
3.6% [0.9%, 19.0%] 24
Regressions ❌
(secondary)
3.2% [2.2%, 4.2%] 2
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 3.6% [0.9%, 19.0%] 24

Binary size

Results

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
1.5% [0.1%, 4.7%] 75
Regressions ❌
(secondary)
2.5% [0.8%, 4.1%] 76
Improvements ✅
(primary)
- - 0
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 1.5% [0.1%, 4.7%] 75

Bootstrap: 679.119s -> 683.166s (0.60%)
Artifact size: 316.14 MiB -> 317.49 MiB (0.43%)

@rustbot rustbot added perf-regression Performance regression. and removed S-waiting-on-perf Status: Waiting on a perf run to be completed. labels Apr 17, 2024
@Voultapher
Copy link
Contributor Author

Voultapher commented Apr 17, 2024

The binary-size results are inline with what we expected, given that slice::sort is more prevalent than slice::sort_unstable it makes sense that the regressions outweigh the improvements.

Regarding compile-times, we looked at those in our analysis here and here. The instruction count metric does not account for gains via parallelizability, right?

@orlp
Copy link
Contributor

orlp commented Apr 17, 2024

One thing that I find particularly strange is a 4.31% regression in helloworld-tiny, which doesn't call sort. Is this just due to the sort call in backtrace-rs?

@rust-timer

This comment has been minimized.

@rust-timer
Copy link
Collaborator

Finished benchmarking commit (ae5dc93): comparison URL.

Overall result: ❌✅ regressions and improvements - ACTION NEEDED

Benchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. While you can manually mark this PR as fit for rollup, we strongly recommend not doing so since this PR may lead to changes in compiler perf.

Next Steps: If you can justify the regressions found in this try perf run, please indicate this with @rustbot label: +perf-regression-triaged along with sufficient written justification. If you cannot justify the regressions please fix the regressions and do another perf run. If the next run shows neutral or positive results, the label will be automatically removed.

@bors rollup=never
@rustbot label: -S-waiting-on-perf +perf-regression

Instruction count

This is a highly reliable metric that was used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
2.0% [0.2%, 18.0%] 45
Regressions ❌
(secondary)
1.6% [0.5%, 3.5%] 4
Improvements ✅
(primary)
-0.7% [-1.2%, -0.3%] 2
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 1.8% [-1.2%, 18.0%] 47

Max RSS (memory usage)

Results (primary 2.6%)

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
3.4% [0.8%, 10.8%] 6
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
-2.6% [-2.6%, -2.6%] 1
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 2.6% [-2.6%, 10.8%] 7

Cycles

Results (primary 4.0%, secondary 3.0%)

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
4.3% [0.8%, 18.2%] 16
Regressions ❌
(secondary)
3.0% [1.6%, 4.6%] 16
Improvements ✅
(primary)
-1.2% [-1.2%, -1.2%] 1
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 4.0% [-1.2%, 18.2%] 17

Binary size

Results (primary 1.5%, secondary 2.5%)

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
1.6% [0.0%, 3.9%] 76
Regressions ❌
(secondary)
2.5% [0.9%, 4.4%] 76
Improvements ✅
(primary)
-0.6% [-0.6%, -0.6%] 1
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 1.5% [-0.6%, 3.9%] 77

Bootstrap: 673.177s -> 678.436s (0.78%)
Artifact size: 320.50 MiB -> 323.64 MiB (0.98%)

@rustbot rustbot removed the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Jun 17, 2024
@Voultapher
Copy link
Contributor Author

Voultapher commented Jun 17, 2024

So it went from before 54 affected cases with a mean regression of 1.8%, to now 47 affected cases with a mean regression of 1.8%. It's a different baseline master, so these numbers are not directly comparable, but the end effect remains mostly the same. Honestly, the thing that suffered the most is readability of the small-sort selection.

EDIT: I suspect this compile time benchmark is more sensitive to slice::sort than slice::sort_unstable as the former is both more prevalent and usually used with heavier types.

EDIT2:

Running our own compile-time benchmarks for slice::sort_unstable as outlined in the design documents.

Before:

Benchmark 1: cargo build
  Time (mean ± σ):      2.208 s ±  0.017 s    [User: 5.290 s, System: 0.379 s]
  Range (min … max):    2.189 s …  2.222 s    3 runs

Benchmark 1: cargo build --release
  Time (mean ± σ):      5.552 s ±  0.023 s    [User: 13.273 s, System: 0.221 s]
  Range (min … max):    5.525 s …  5.566 s    3 runs

After: (with fixed CopyMarker)

Benchmark 1: cargo build
  Time (mean ± σ):      2.501 s ±  0.004 s    [User: 5.969 s, System: 0.357 s]
  Range (min … max):    2.497 s …  2.505 s    3 runs
 
Benchmark 1: cargo build --release
  Time (mean ± σ):      6.122 s ±  0.073 s    [User: 14.480 s, System: 0.213 s]
  Range (min … max):    6.042 s …  6.186 s    3 runs

So a noticeable regression.

@Voultapher
Copy link
Contributor Author

I think this should resolve the last open point, @thomcc right?

@thomcc
Copy link
Member

thomcc commented Jun 17, 2024

Looks good to me. Thanks for all the work on this.

@bors r+ rollup=never

@bors
Copy link
Contributor

bors commented Jun 17, 2024

📌 Commit 032ad4c has been approved by thomcc

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jun 17, 2024
@RalfJung
Copy link
Member

@bors r-

needs confirmation that the Miri test does not get too slow

@bors bors added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Jun 17, 2024
The changes made only a limited improvement for the current small
miri coverage and in general test coverage of the sort implementations.
But they exploded test times from ~13s to ~240s, which is not deemed
worth it.
@Voultapher
Copy link
Contributor Author

I've reverted the panic_safety test changes, with the reasoning given in the commit message and the change conversation.

@Voultapher
Copy link
Contributor Author

Voultapher commented Jun 17, 2024

Doing a sanity test, I noticed with the recent changes hot-u64-random-10000 went from ~81us to ~99us, which means something went wrong, when refactoring the const_trait usage. Turns out I accidentally deleted the CopyMarker impl which made it never pick the Copy heuristic trait impls. Fix incoming.

Due to refactoring the const_trait usage, the CopyMarker impl was
accidentally deleted, which had the consequence that the Copy
specialization for the small-sort was never picked.
@Voultapher
Copy link
Contributor Author

Let's please re-run the timer run, I suspect we will see slightly more pronounced changes to before now.

@Kobzol
Copy link
Contributor

Kobzol commented Jun 17, 2024

@bors try @rust-timer queue

@rust-timer

This comment has been minimized.

@rustbot rustbot added the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Jun 17, 2024
@bors
Copy link
Contributor

bors commented Jun 17, 2024

⌛ Trying commit b7deff3 with merge 24b359fb97924de5ddc5080af6a22ee7b5147b06...

bors added a commit to rust-lang-ci/rust that referenced this pull request Jun 17, 2024
Replace sort implementations

This PR replaces the sort implementations with tailor-made ones that strike a balance of run-time, compile-time and binary-size, yielding run-time and compile-time improvements. Regressing binary-size for `slice::sort` while improving it for `slice::sort_unstable`. All while upholding the existing soft and hard safety guarantees, and even extending the soft guarantees, detecting strict weak ordering violations with a high chance and reporting it to users via a panic.

* `slice::sort` -> driftsort [design document](https://github.com/Voultapher/sort-research-rs/blob/main/writeup/driftsort_introduction/text.md), includes detailed benchmarks and analysis.

* `slice::sort_unstable` -> ipnsort [design document](https://github.com/Voultapher/sort-research-rs/blob/main/writeup/ipnsort_introduction/text.md), includes detailed benchmarks and analysis.

#### Why should we change the sort implementations?

In the [2023 Rust survey](https://blog.rust-lang.org/2024/02/19/2023-Rust-Annual-Survey-2023-results.html#challenges), one of the questions was: "In your opinion, how should work on the following aspects of Rust be prioritized?". The second place was "Runtime performance" and the third one "Compile Times". This PR aims to improve both.

#### Why is this one big PR and not multiple?

* The current documentation gives performance recommendations for `slice::sort` and `slice::sort_unstable`. If for example only one of them were to be changed, this advice would be misleading for some Rust versions. By replacing them atomically, the advice remains largely unchanged, and users don't have to change their code.
* driftsort and ipnsort share a substantial part of their implementations.
* The implementation of `select_nth_unstable` uses internals of `slice::sort_unstable`, which makes it impractical to split changes.

---

This PR is a collaboration with `@orlp.`
@bors
Copy link
Contributor

bors commented Jun 17, 2024

☀️ Try build successful - checks-actions
Build commit: 24b359f (24b359fb97924de5ddc5080af6a22ee7b5147b06)

@rust-timer

This comment has been minimized.

@rust-timer
Copy link
Collaborator

Finished benchmarking commit (24b359f): comparison URL.

Overall result: ❌ regressions - ACTION NEEDED

Benchmarking this pull request likely means that it is perf-sensitive, so we're automatically marking it as not fit for rolling up. While you can manually mark this PR as fit for rollup, we strongly recommend not doing so since this PR may lead to changes in compiler perf.

Next Steps: If you can justify the regressions found in this try perf run, please indicate this with @rustbot label: +perf-regression-triaged along with sufficient written justification. If you cannot justify the regressions please fix the regressions and do another perf run. If the next run shows neutral or positive results, the label will be automatically removed.

@bors rollup=never
@rustbot label: -S-waiting-on-perf +perf-regression

Instruction count

This is a highly reliable metric that was used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
1.9% [0.2%, 18.0%] 51
Regressions ❌
(secondary)
1.6% [0.1%, 3.8%] 4
Improvements ✅
(primary)
-0.3% [-0.3%, -0.3%] 1
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 1.9% [-0.3%, 18.0%] 52

Max RSS (memory usage)

Results (primary 2.4%)

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
3.1% [1.6%, 6.4%] 7
Regressions ❌
(secondary)
- - 0
Improvements ✅
(primary)
-2.2% [-2.2%, -2.2%] 1
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 2.4% [-2.2%, 6.4%] 8

Cycles

Results (primary 3.3%, secondary -0.6%)

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
3.5% [0.7%, 18.1%] 25
Regressions ❌
(secondary)
3.7% [2.1%, 4.3%] 4
Improvements ✅
(primary)
-1.9% [-1.9%, -1.9%] 1
Improvements ✅
(secondary)
-3.1% [-7.1%, -2.1%] 7
All ❌✅ (primary) 3.3% [-1.9%, 18.1%] 26

Binary size

Results (primary 1.6%, secondary 2.4%)

This is a less reliable metric that may be of interest but was not used to determine the overall result at the top of this comment.

mean range count
Regressions ❌
(primary)
1.6% [0.4%, 3.9%] 74
Regressions ❌
(secondary)
2.4% [0.9%, 4.4%] 76
Improvements ✅
(primary)
-0.4% [-0.4%, -0.3%] 2
Improvements ✅
(secondary)
- - 0
All ❌✅ (primary) 1.6% [-0.4%, 3.9%] 76

Bootstrap: 670.379s -> 677.734s (1.10%)
Artifact size: 320.52 MiB -> 323.62 MiB (0.97%)

@rustbot rustbot removed the S-waiting-on-perf Status: Waiting on a perf run to be completed. label Jun 18, 2024
@Voultapher
Copy link
Contributor Author

Ok, so the mean regression of the affected cases went from 1.8% to 1.9%. I'd say the previous reasoning doesn't change.

@Voultapher
Copy link
Contributor Author

Voultapher commented Jun 18, 2024

I think there should be no more outstanding issues, from my side it's good to merge.

@thomcc
Copy link
Member

thomcc commented Jun 18, 2024

@RalfJung is it fine from miri's end now?

@RalfJung
Copy link
Member

This no longer has any miri-related changes, so -- yes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
perf-regression Performance regression. S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet